﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CSF.Security.Data;

namespace CSF.Security.BLL
{
    /// <summary>
    /// 用来执行用户操作权限验证的工具类
    /// </summary>
    public static class Authorizer
    {
        private static object _locker = new object();

        private static Dictionary<string, PermissionTree> _permissionTrees = new Dictionary<string, PermissionTree>();

        private static Dictionary<string, int[]> _userRoles = new Dictionary<string,int[]>();

        public static void ResetPermissionTree(string appCode)
        {
            lock (_locker)
            {
                _permissionTrees.Remove(appCode);
            }
        }

        public static void ResetUserRole(string userName)
        {
            lock (_locker)
            {
                _userRoles.Remove(userName);
            }
        }

        public static bool CheckPermission(string appCode, string sessionId, string path, string queryString, string formString)
        {
            lock (_locker)
            {
                bool result = true;

                var session = Authenticator.VerifySession(sessionId);
                if (session != null)
                {
                    int permissionId = 0;
                    int applicationId = session.ApplicationId;

                    bool allow = session.UserName.Equals("Admin", StringComparison.OrdinalIgnoreCase);

                    UserAccountApplicationBLL uaBll = new UserAccountApplicationBLL();
                    if (allow || uaBll.CheckUser(session.UserId, appCode))
                    {
                        PermissionTree tree = GetTreeByAppCode(appCode);
                        if (tree != null)
                        {
                            var node = tree.Find(path);
                            if (node != null)
                            {
                                permissionId = node.Permission.Id;
                                applicationId = node.Permission.ApplicationId;
                                if (!allow && node.Roles != null && node.Roles.Count() > 0)
                                {
                                    var userRoles = GetUserRoles(session.UserName);
                                    if (userRoles != null && userRoles.Count() > 0)
                                    {
                                        // 看结合是否有重叠
                                        allow = AnyIntersect(node.Roles, userRoles);
                                    }
                                }
                            }
                            else
                                allow = true;
                        }
                        else
                            allow = true;
                    }
                    if (allow)
                    {
                        //  记录操作日志
                        UserActionLog log = new UserActionLog()
                        {
                            ApplicationId = applicationId,
                            SessionId = sessionId,
                            UserName = session.UserName,
                            PermissionId = permissionId,
                            Path = path,
                            QueryString = queryString,
                            FormString = formString,
                            ActionTime = DateTime.Now
                        };
                        UserActionLogBLL ualBll = new UserActionLogBLL();
                        ualBll.Insert(log);
                    }
                    result = allow;
                }
                return result;
            }
        }

        private static PermissionTree GetTreeByAppCode(string appCode)
        {
            PermissionTree result = null;
            if (!_permissionTrees.ContainsKey(appCode))
            {
                PermissionBLL pbll = new PermissionBLL();
                var permissions = pbll.GetByAppCode(appCode);

                result = PermissionTree.Create(permissions);

                _permissionTrees[appCode] = result;
            }
            else
            {
                result = _permissionTrees[appCode];
            }
            return result;
        }

        /// <summary>
        /// 读取某个用户所属角色
        /// 从缓存中读取，如果缓存中不存在，则读取数据库，同时保留副本到缓存中。
        /// </summary>
        /// <param name="userName">用户名</param>
        /// <returns></returns>
        private static int[] GetUserRoles(string userName)
        {

            if (!_userRoles.ContainsKey(userName))
            {
                UserAccountRoleBLL bll = new UserAccountRoleBLL();
                var rolesList = bll.GetRoleIdsByUser(userName);
                int[] roles = null;
                if (rolesList != null)
                {
                    roles = rolesList.ToArray();
                    _userRoles.Add(userName, roles);
                }
                return roles;
            }
            else
                return _userRoles[userName];

        }

        public static bool AnyIntersect<TElement>(IEnumerable<TElement> list1, IEnumerable<TElement> list2)
            where TElement : IComparable
        {
            var i1 = list1.OrderBy(p => p).GetEnumerator();
            var i2 = list2.OrderBy(p => p).GetEnumerator();
            bool next = i1.MoveNext() && i2.MoveNext();

            bool result = false;

            while (next)
            {
                int c = i1.Current.CompareTo(i2.Current);
                if (c == 0)
                {
                    result = true;
                    break;
                }
                else if (c < 0)
                {
                    next = i1.MoveNext();
                }
                else
                {
                    next = i2.MoveNext();
                }
            };

            return result;
        }
    }
}
